package com.freeter.modules.gjs.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.freeter.modules.gjs.entity.*;
import com.freeter.modules.gjs.mapper.*;
import com.freeter.modules.gjs.service.EmailService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 业务逻辑处理器
 * 负责处理各种业务文件的逻辑，从Node.js版本移植
 */
@Service
public class BusinessLogicProcessorForFile {
    
    private static final Logger log = LoggerFactory.getLogger(BusinessLogicProcessorForFile.class);
    
    @Autowired
    private GrMapper grMapper;
    
    @Autowired
    private GrItemMapper grItemMapper;
    
    @Autowired
    private StockStatusMapper stockStatusMapper;
    
    @Autowired
    private TransactionMapper transactionMapper;
    
    @Autowired
    private MstrSiteMapper mstrSiteMapper;
    
    @Autowired
    private MstrItemsMapper mstrItemsMapper;
    
    @Autowired
    private MstrUomMapper mstrUomMapper;
    
    @Autowired
    private MstrCat00Mapper mstrCat00Mapper;
    
    @Autowired
    private MstrCat01Mapper mstrCat01Mapper;
    
    @Autowired
    private MstrCat02Mapper mstrCat02Mapper;
    
    @Autowired
    private TransferRequestMapper transferRequestMapper;
    
    @Autowired
    private DamageReportMapper damageReportMapper;
    
    @Autowired
    private UserMapper userMapper;
    
    @Autowired
    private TransferItemsMapper transferItemsMapper;
    

    
    @Autowired
    private ObjectMapper objectMapper;
    
    @Autowired
    private EmailService emailService;
    
    private String calcTicketFolder;
    
    public void setCalcTicketFolder(String calcTicketFolder) {
        this.calcTicketFolder = calcTicketFolder;
    }
    
    /**
     * 处理收货单文件
     */
    @Transactional(rollbackFor = Exception.class)
    public void processGrFile(Path filePath) {
        log.info("开始处理收货单文件: {}", filePath);
        
        try {
            String content = new String(Files.readAllBytes(filePath), StandardCharsets.UTF_8);
            JsonNode gr = objectMapper.readTree(content);
            
            String action = gr.get("action").asText();
            log.info("收货单操作类型: {}", action);
            
            if ("ADD".equals(action)) {
                processGrAdd(gr, filePath);
            } else if ("CANCEL".equals(action)) {
                processGrCancel(gr, filePath);
            } else {
                log.warn("未知的收货单操作类型: {}", action);
                Files.deleteIfExists(filePath);
            }
            
        } catch (IOException e) {
            log.error("处理收货单文件失败: {}", filePath, e);
        } catch (Exception e) {
            log.error("处理收货单文件失败: {}", filePath, e);
        }
    }
    
    /**
     * 处理收货单新增操作
     */
    @Transactional(rollbackFor = Exception.class)
    private void processGrAdd(JsonNode gr, Path filePath) {
        log.info("处理收货单新增操作: {}", gr.get("ID").asText());
        
        try {
            // 1. 处理项目（站点）主数据
            Long siteId = processSiteData(gr.get("ProjectNo").asText());
            
            // 2. 处理收货单明细
            JsonNode items = gr.get("items");
            List<Map<String, Object>> writeDataList = new ArrayList<>();
            
            for (JsonNode item : items) {
                // 处理计量单位
                Long uomId = processUomData(item.get("Uom").asText());
                
                // 处理物品主数据
                Long itemId = processItemData(item, uomId);
                
                // 处理库存状态
                Long stockId = processStockStatus(item, siteId, itemId, uomId);
                
                // 处理交易记录
                Long transactionId = processTransactionRecord(gr, item, stockId, siteId);
                
                // 如果不是新批次，添加到写入列表
                if (!isNewBatch(stockId)) {
                    writeDataList.add(createTransactionData(gr, item, stockId, siteId, transactionId));
                }
            }
            
            // 3. 更新收货单状态
            updateGrStatus(gr.get("ID").asLong());
            
            // 4. 写入交易文件
            for (Map<String, Object> writeData : writeDataList) {
                writeTransactionFile(writeData);
            }
            
            // 5. 删除原文件
            Files.deleteIfExists(filePath);
            
            log.info("收货单新增处理完成: {}", gr.get("ID").asText());
            
        } catch (IOException e) {
            log.error("处理收货单新增失败", e);
            throw new RuntimeException(e);
        } catch (Exception e) {
            log.error("处理收货单新增失败", e);
            throw e;
        }
    }
    
    /**
     * 处理收货单取消操作
     */
    @Transactional(rollbackFor = Exception.class)
    private void processGrCancel(JsonNode gr, Path filePath) {
        log.info("处理收货单取消操作: {}", gr.get("RefNo").asText());
        
        try {
            // 1. 查找相关交易记录
            List<Map<String, Object>> transactions = findTransactionsByRefNo(gr.get("RefNo").asText());
            
            // 2. 回滚库存数量
            for (Map<String, Object> transaction : transactions) {
                Long stockId = (Long) transaction.get("stock_id");
                BigDecimal qty = (BigDecimal) transaction.get("qty");
                
                // 减少库存数量
                updateStockQuantity(stockId, qty.negate());
                
                // 标记交易记录为已删除
                markTransactionAsDeleted((Long) transaction.get("id"));
            }
            
            // 3. 更新收货单状态
            updateGrStatus(gr.get("ID").asLong());
            
            // 4. 删除原文件
            Files.deleteIfExists(filePath);
            
            log.info("收货单取消处理完成: {}", gr.get("RefNo").asText());
            
        } catch (IOException e) {
            log.error("处理收货单取消失败", e);
            throw new RuntimeException(e);
        } catch (Exception e) {
            log.error("处理收货单取消失败", e);
            throw e;
        }
    }
    
    /**
     * 处理交易文件
     */
    @Transactional(rollbackFor = Exception.class)
    public void processTransactionFile(Path filePath) {
        log.info("开始处理交易文件: {}", filePath);
        
        try {
            String content = new String(Files.readAllBytes(filePath), StandardCharsets.UTF_8);
            JsonNode transaction = objectMapper.readTree(content);
            
            int calcStatus = transaction.get("calc_status").asInt();
            if (calcStatus == 0) {
                String source = transaction.get("source").asText();
                
                if ("GR".equals(source)) {
                    processGrTransaction(transaction, filePath);
                } else if ("Use".equals(source)) {
                    processUseTransaction(transaction, filePath);
                } else if ("Damage".equals(source)) {
                    processDamageTransaction(transaction, filePath);
                } else {
                    log.warn("未知的交易来源: {}", source);
                    Files.deleteIfExists(filePath);
                }
            } else {
                log.info("交易已处理，跳过: {}", filePath);
                Files.deleteIfExists(filePath);
            }
            
        } catch (IOException e) {
            log.error("处理交易文件失败: {}", filePath, e);
        } catch (Exception e) {
            log.error("处理交易文件失败: {}", filePath, e);
        }
    }
    
    /**
     * 处理GR来源的交易
     */
    @Transactional(rollbackFor = Exception.class)
    private void processGrTransaction(JsonNode transaction, Path filePath) {
        log.info("处理GR交易: {}", transaction.get("id").asText());
        
        try {
            Long stockId = transaction.get("stock_id").asLong();
            BigDecimal qty = new BigDecimal(transaction.get("qty").asText());
            
            // 获取当前库存
            StockStatus stock = getStockStatus(stockId);
            if (stock != null) {
                BigDecimal currentQty = new BigDecimal ( stock.getStockQty());

                BigDecimal finalQty = currentQty.add(qty);
                
                // 更新库存数量
                updateStockQuantity(stockId, finalQty);
                
                // 更新交易状态
                updateTransactionStatus(transaction.get("id").asLong(), finalQty);
                
                // 删除原文件
                Files.deleteIfExists(filePath);
                
                log.info("GR交易处理完成: {}", transaction.get("id").asText());
            }
            
        } catch (IOException e) {
            log.error("处理GR交易失败", e);
            throw new RuntimeException(e);
        } catch (Exception e) {
            log.error("处理GR交易失败", e);
            throw e;
        }
    }
    
    /**
     * 处理Use来源的交易
     */
    @Transactional(rollbackFor = Exception.class)
    private void processUseTransaction(JsonNode transaction, Path filePath) {
        log.info("处理Use交易: {}", transaction.get("id").asText());
        
        try {
            Long stockId = transaction.get("stock_id").asLong();
            BigDecimal qty = new BigDecimal(transaction.get("qty").asText());
            
            // 获取当前库存
            StockStatus stock = getStockStatus(stockId);
            if (stock != null) {
                BigDecimal currentQty = new BigDecimal ( stock.getStockQty());
                BigDecimal finalQty = currentQty.subtract(qty);
                
                // 更新库存数量
                updateStockQuantity(stockId, finalQty);
                
                // 更新交易状态
                updateTransactionStatus(transaction.get("id").asLong(), finalQty);
                
                // 删除原文件
                Files.deleteIfExists(filePath);
                
                log.info("Use交易处理完成: {}", transaction.get("id").asText());
            }
            
        } catch (IOException e) {
            log.error("处理Use交易失败", e);
            throw new RuntimeException(e);
        } catch (Exception e) {
            log.error("处理Use交易失败", e);
            throw e;
        }
    }
    
    /**
     * 处理Damage来源的交易
     */
    @Transactional(rollbackFor = Exception.class)
    private void processDamageTransaction(JsonNode transaction, Path filePath) {
        log.info("处理Damage交易: {}", transaction.get("id").asText());
        
        try {
            Long stockId = transaction.get("stock_id").asLong();
            BigDecimal qty = new BigDecimal(transaction.get("qty").asText());
            
            // 获取当前库存
            StockStatus stock = getStockStatus(stockId);
            if (stock != null) {
                BigDecimal currentQty = new BigDecimal ( stock.getStockQty());
                BigDecimal currentHoldQty = new BigDecimal ( stock.getHoldQty());
                BigDecimal finalQty = currentQty.subtract(qty);
                BigDecimal finalHoldQty = currentHoldQty.subtract(qty);
                
                // 更新库存数量和冻结数量
                updateStockAndHoldQuantity(stockId, finalQty, finalHoldQty);
                
                // 更新交易状态
                updateTransactionStatus(transaction.get("id").asLong(), finalQty);
                
                // 删除原文件
                Files.deleteIfExists(filePath);
                
                log.info("Damage交易处理完成: {}", transaction.get("id").asText());
            }
            
        } catch (IOException e) {
            log.error("处理Damage交易失败", e);
            throw new RuntimeException(e);
        } catch (Exception e) {
            log.error("处理Damage交易失败", e);
            throw e;
        }
    }
    
    /**
     * 处理调拨申请文件
     */
    @Transactional(rollbackFor = Exception.class)
    public void processTransferRequestFile(Path filePath) {
        log.info("开始处理调拨申请文件: {}", filePath);
        
        try {
            String content = new String(Files.readAllBytes(filePath), StandardCharsets.UTF_8);
            JsonNode transferRequest = objectMapper.readTree(content);
            
            String status = transferRequest.get("status").asText();
            
            if ("Pending".equals(status)) {
                processPendingTransferRequest(transferRequest, filePath);
            } else if ("Approved".equals(status) || "Rejected".equals(status)) {
                processApprovedRejectedTransferRequest(transferRequest, filePath);
            } else {
                log.warn("未知的调拨申请状态: {}", status);
                Files.deleteIfExists(filePath);
            }
            
        } catch (IOException e) {
            log.error("处理调拨申请文件失败: {}", filePath, e);
        } catch (Exception e) {
            log.error("处理调拨申请文件失败: {}", filePath, e);
        }
    }
    
    /**
     * 处理待审批的调拨申请
     */
    private void processPendingTransferRequest(JsonNode transferRequest, Path filePath) {
        log.info("处理待审批调拨申请: {}", transferRequest.get("id").asText());
        
        try {
            // 查找有权限的用户
            List<Map<String, Object>> users = findUsersWithTransferPermission();
            
            for (Map<String, Object> user : users) {
                String email = (String) user.get("login");
                if (isValidEmail(email)) {
                    // 获取调拨物品信息
                    List<Map<String, Object>> transferItems = getTransferItems(transferRequest.get("id").asLong(), user);
                    
                    if (!transferItems.isEmpty()) {
                        // 发送邮件通知
                        sendTransferRequestEmail(email, transferRequest, transferItems, user);
                        
                        // 如果有备用邮箱，也发送通知
                        String altEmail = (String) user.get("alt_email");
                        if (altEmail != null && isValidEmail(altEmail)) {
                            sendTransferRequestEmail(altEmail, transferRequest, transferItems, user);
                        }
                    }
                }
            }
            
            // 删除原文件
            Files.deleteIfExists(filePath);
            
        } catch (Exception e) {
            log.error("处理待审批调拨申请失败", e);
        }
    }
    
    /**
     * 处理已审批/拒绝的调拨申请
     */
    private void processApprovedRejectedTransferRequest(JsonNode transferRequest, Path filePath) {
        log.info("处理已审批/拒绝调拨申请: {}", transferRequest.get("id").asText());
        
        try {
            // 获取申请人信息
            Map<String, Object> requester = getTransferRequestRequester(transferRequest.get("id").asLong());
            
            if (requester != null) {
                String email = (String) requester.get("login");
                if (isValidEmail(email)) {
                    // 获取调拨物品信息
                    List<Map<String, Object>> transferItems = getTransferItemsForNotification(transferRequest.get("id").asLong());
                    
                    if (!transferItems.isEmpty()) {
                        // 发送结果通知邮件
                        sendTransferResultEmail(email, transferRequest, transferItems);
                    }
                }
            }
            
            // 删除原文件
            Files.deleteIfExists(filePath);
            
        } catch (Exception e) {
            log.error("处理已审批/拒绝调拨申请失败", e);
        }
    }
    
    /**
     * 处理损坏报告文件
     */
    @Transactional(rollbackFor = Exception.class)
    public void processDamageReportFile(Path filePath) {
        log.info("开始处理损坏报告文件: {}", filePath);
        
        try {
            String content = new String(Files.readAllBytes(filePath), StandardCharsets.UTF_8);
            JsonNode damageReport = objectMapper.readTree(content);
            
            String status = damageReport.get("status").asText();
            
            if ("Pending".equals(status)) {
                processPendingDamageReport(damageReport, filePath);
            } else {
                log.warn("未知的损坏报告状态: {}", status);
                Files.deleteIfExists(filePath);
            }
            
        } catch (Exception e) {
            log.error("处理损坏报告文件失败: {}", filePath, e);
        }
    }
    
    /**
     * 处理待确认的损坏报告
     */
    private void processPendingDamageReport(JsonNode damageReport, Path filePath) {
        log.info("处理待确认损坏报告: {}", damageReport.get("id").asText());
        
        try {
            // 查找有权限的用户
            List<Map<String, Object>> users = findUsersWithDamagePermission();
            
            for (Map<String, Object> user : users) {
                String email = (String) user.get("login");
                if (isValidEmail(email)) {
                    // 获取损坏报告信息
                    List<Map<String, Object>> damageInfo = getDamageReportInfo(damageReport.get("id").asLong(), user);
                    
                    if (!damageInfo.isEmpty()) {
                        // 发送邮件通知
                        sendDamageReportEmail(email, damageReport, damageInfo, user);
                        
                        // 如果有备用邮箱，也发送通知
                        String altEmail = (String) user.get("alt_email");
                        if (altEmail != null && isValidEmail(altEmail)) {
                            sendDamageReportEmail(altEmail, damageReport, damageInfo, user);
                        }
                    }
                }
            }
            
            // 删除原文件
            Files.deleteIfExists(filePath);
            
        } catch (Exception e) {
            log.error("处理待确认损坏报告失败", e);
        }
    }
    
    // ==================== 数据库操作方法 ====================
    
    /**
     * 处理站点数据
     */
    private Long processSiteData(String projectCode) {
        EntityWrapper<MstrSite> wrapper = new EntityWrapper<>();
        wrapper.eq("project_code", projectCode).eq("is_deleted", 0);
        List<MstrSite> sites = mstrSiteMapper.selectList(wrapper);
        
        if (sites.isEmpty()) {
            // 插入新站点
            MstrSite newSite = new MstrSite();
            newSite.setProjectCode(projectCode);
            newSite.setIsDeleted(0);
            mstrSiteMapper.insert(newSite);
            
            // 获取插入的ID
            sites = mstrSiteMapper.selectList(wrapper);
        }
        
        return sites.get(0).getId();
    }
    
    /**
     * 处理计量单位数据
     */
    private Long processUomData(String uomDesc) {
        EntityWrapper<MstrUom> wrapper = new EntityWrapper<>();
        wrapper.eq("desc_en", uomDesc).eq("is_deleted", 0);
        List<MstrUom> uoms = mstrUomMapper.selectList(wrapper);
        
        if (uoms.isEmpty()) {
            // 插入新计量单位
            MstrUom newUom = new MstrUom();
            newUom.setDescEn(uomDesc);
            newUom.setIsDeleted(0);
            mstrUomMapper.insert(newUom);
            
            // 获取插入的ID
            uoms = mstrUomMapper.selectList(wrapper);
        }
        
        return uoms.get(0).getId();
    }
    
    /**
     * 处理物品数据
     */
    private Long processItemData(JsonNode item, Long uomId) {
        String itemDesc = item.get("ItemDesc").asText();
        EntityWrapper<MstrItems> wrapper = new EntityWrapper<>();
        wrapper.eq("item_desc", itemDesc).eq("uom_id", uomId).eq("is_deleted", 0);
        List<MstrItems> items = mstrItemsMapper.selectList(wrapper);
        
        if (items.isEmpty()) {
            // 处理物品分类
            Long catId = processItemCategory(item);
            
            // 插入新物品
            MstrItems newItem = new MstrItems();
            newItem.setCatId(catId.toString());
            newItem.setItemBarcode(item.get("ProdCat").asText());
            newItem.setItemDesc(itemDesc);
            newItem.setUomId(uomId);
            newItem.setCreatedt(new Date());
            newItem.setIsDeleted(0);
            mstrItemsMapper.insert(newItem);
            
            // 获取插入的ID
            items = mstrItemsMapper.selectList(wrapper);
        }
        
        return Long.valueOf(items.get(0).getCatId());
    }
    
    /**
     * 处理物品分类
     */
    private Long processItemCategory(JsonNode item) {
        String prodCat = item.get("ProdCat").asText();
        if (prodCat == null || prodCat.isEmpty()) {
            return null;
        }
        
        // 按4位一组分类
        String cat00Code = prodCat.substring(0, Math.min(4, prodCat.length()));
        String cat01Code = prodCat.length() >= 8 ? prodCat.substring(4, 8) : "";
        String cat02Code = prodCat.length() >= 12 ? prodCat.substring(8, 12) : "";
        
        // 处理第一级分类
        Long cat00Id = processCategoryLevel("mstr_cat_00", cat00Code, null);
        
        // 处理第二级分类
        Long cat01Id = null;
        if (!cat01Code.isEmpty()) {
            cat01Id = processCategoryLevel("mstr_cat_01", cat01Code, cat00Id);
        }
        
        // 处理第三级分类
        Long cat02Id = null;
        if (!cat02Code.isEmpty()) {
            cat02Id = processCategoryLevel("mstr_cat_02", cat02Code, cat01Id);
        }
        
        return cat02Id != null ? cat02Id : (cat01Id != null ? cat01Id : cat00Id);
    }
    
    /**
     * 处理分类层级
     */
    private Long processCategoryLevel(String tableName, String code, Long parentId) {
        // 根据表名选择对应的Mapper
        if ("mstr_cat_00".equals(tableName)) {
            EntityWrapper<MstrCat00> wrapper = new EntityWrapper<>();
            wrapper.eq("id", code).eq("is_deleted", 0);
            List<MstrCat00> categories = mstrCat00Mapper.selectList(wrapper);
            
            if (categories.isEmpty()) {
                MstrCat00 newCat = new MstrCat00();
                newCat.setId(Long.parseLong(code));
                newCat.setDescEn(code);
                newCat.setIsDeleted(0);
                mstrCat00Mapper.insert(newCat);
                categories = mstrCat00Mapper.selectList(wrapper);
            }
            return categories.get(0).getId();
        } else if ("mstr_cat_01".equals(tableName)) {
            EntityWrapper<MstrCat01> wrapper = new EntityWrapper<>();
            wrapper.eq("id", code).eq("is_deleted", 0);
            List<MstrCat01> categories = mstrCat01Mapper.selectList(wrapper);
            
            if (categories.isEmpty()) {
                MstrCat01 newCat = new MstrCat01();
                newCat.setId(Long.parseLong(code));
                newCat.setDescEn(code);
                newCat.setPlevel(parentId);
                newCat.setIsDeleted(0);
                mstrCat01Mapper.insert(newCat);
                categories = mstrCat01Mapper.selectList(wrapper);
            }
            return categories.get(0).getId();
        } else if ("mstr_cat_02".equals(tableName)) {
            EntityWrapper<MstrCat02> wrapper = new EntityWrapper<>();
            wrapper.eq("id", code).eq("is_deleted", 0);
            List<MstrCat02> categories = mstrCat02Mapper.selectList(wrapper);
            
            if (categories.isEmpty()) {
                MstrCat02 newCat = new MstrCat02();
                newCat.setId(Long.parseLong(code));
                newCat.setDescEn(code);
                newCat.setPlevel(parentId);
                newCat.setIsDeleted(0);
                mstrCat02Mapper.insert(newCat);
                categories = mstrCat02Mapper.selectList(wrapper);
            }
            return categories.get(0).getId();
        }
        
        return null;
    }
    
    /**
     * 处理库存状态
     */
    private Long processStockStatus(JsonNode item, Long siteId, Long itemId, Long uomId) {
        // 查询现有库存状态
        List<Map<String, Object>> stockList = stockStatusMapper.selectStockStatusBySiteAndItem(siteId, uomId, item.get("ProdCat").asText());
        
        if (!stockList.isEmpty()) {
            // 检查是否存在exp_date为空的库存状态
            List<Map<String, Object>> nullExpStock = stockStatusMapper.selectStockStatusWithNullExpDate(siteId, uomId, item.get("ProdCat").asText());
            
            if (!nullExpStock.isEmpty()) {
                // 更新现有库存的last_gr时间
                Long stockId = (Long) nullExpStock.get(0).get("id");
                stockStatusMapper.updateLastGr(stockId, LocalDateTime.now());
                return stockId;
            } else {
                // 新批次，获取失效期限
                List<Map<String, Object>> expStock = stockStatusMapper.selectStockStatusWithExpDate(siteId, uomId, item.get("ProdCat").asText());
                
                if (!expStock.isEmpty()) {
                    return createNewStockStatus(item, siteId, itemId, uomId, (Integer) expStock.get(0).get("exp_period"));
                }
            }
        }
        
        // 创建新的库存状态
        return createNewStockStatus(item, siteId, itemId, uomId, null);
    }
    
    /**
     * 创建新的库存状态
     */
    private Long createNewStockStatus(JsonNode item, Long siteId, Long itemId, Long uomId, Integer expPeriod) {
        StockStatus newStock = new StockStatus();
        newStock.setItemBarcode(item.get("ProdCat").asText());
        newStock.setItemDesc(item.get("ItemDesc").asText());
        newStock.setStockQty(item.get("Qty").asDouble());
        newStock.setExpPeriod(expPeriod != null ? expPeriod.toString() : null);
        
        LocalDateTime now = LocalDateTime.now();
        if (expPeriod != null) {
            // 计算过期日期（这里简化处理，实际应该根据数据库的DATE_ADD函数）
            newStock.setItemExpDate(now.plusMonths(expPeriod).toString());
        }
        
        newStock.setRecordDate(new Date());
        
        stockStatusMapper.insert(newStock);
        return newStock.getId();
    }
    
    /**
     * 处理交易记录
     */
    private Long processTransactionRecord(JsonNode gr, JsonNode item, Long stockId, Long siteId) {
        boolean isNewBatch = isNewBatch(stockId);
        BigDecimal qty = new BigDecimal(item.get("Qty").asText());
        
        Transaction transaction = new Transaction();
        transaction.setStockId(stockId);
        transaction.setSuppName(gr.get("SuppNam").asText());
        transaction.setRefNo(gr.get("RefNo").asText());
        transaction.setPoNo(gr.get("PoNo").asText());
        transaction.setPrNo(gr.get("PrNo").asText());
        transaction.setScForm(item.get("ScForm").asText());
        transaction.setQty(qty);
        transaction.setRemarks(gr.get("Remarks").asText());
        transaction.setUponCalc(isNewBatch ? qty : null);
        transaction.setCalcStatus(isNewBatch ? 1 : 0);
        transaction.setDnDirName(gr.get("dn_dir_name").asText());
        transaction.setTmmUrl(gr.get("url").asText());
        transaction.setIsTransfer(0);
        transaction.setRecvSiteId(siteId);
        transaction.setSource("GR");
        transaction.setRecordTime(new Date());
        
        transactionMapper.insert(transaction);
        return transaction.getId();
    }
    
    /**
     * 检查是否为新批次
     */
    private boolean isNewBatch(Long stockId) {
        return stockStatusMapper.countNewBatch(stockId) > 0;
    }
    
    /**
     * 创建交易数据
     */
    private Map<String, Object> createTransactionData(JsonNode gr, JsonNode item, Long stockId, Long siteId, Long transactionId) {
        Map<String, Object> data = new HashMap<>();
        data.put("id", transactionId);
        data.put("stock_id", stockId);
        data.put("supp_name", gr.get("SuppNam").asText());
        data.put("ref_no", gr.get("RefNo").asText());
        data.put("po_no", gr.get("PoNo").asText());
        data.put("pr_no", gr.get("PrNo").asText());
        data.put("sc_form", item.get("ScForm").asText());
        data.put("qty", item.get("Qty").asText());
        data.put("remarks", gr.get("Remarks").asText());
        data.put("upon_calc", null);
        data.put("calc_status", 0);
        data.put("dn_dir_name", gr.get("dn_dir_name").asText());
        data.put("tmm_url", gr.get("url").asText());
        data.put("is_transfer", 0);
        data.put("recv_site_id", siteId);
        data.put("source", "GR");
        return data;
    }
    
    /**
     * 写入交易文件
     */
    private void writeTransactionFile(Map<String, Object> data) {
        try {
            String fileName = UUID.randomUUID().toString() + ".json";
            Path filePath = Paths.get(calcTicketFolder, "transaction", fileName);
            String content = objectMapper.writeValueAsString(data);
            Files.write(filePath, content.getBytes());
            log.info("写入交易文件: {}", filePath);
        } catch (Exception e) {
            log.error("写入交易文件失败", e);
        }
    }
    
    /**
     * 更新收货单状态
     */
    private void updateGrStatus(Long grId) {
        // 更新收货单状态
        Gr gr = grMapper.selectById(grId);
        if (gr != null) {
            gr.setCalcStatus(1);
            grMapper.updateById(gr);
        }
        
        // 更新收货单明细状态
        EntityWrapper<GrItem> wrapper = new EntityWrapper<>();
        wrapper.eq("gr_id", grId);
        List<GrItem> grItems = grItemMapper.selectList(wrapper);
        for (GrItem grItem : grItems) {
            grItem.setCalcStatus(1);
            grItemMapper.updateById(grItem);
        }
    }
    
    /**
     * 查找交易记录
     */
    private List<Map<String, Object>> findTransactionsByRefNo(String refNo) {
        return transactionMapper.selectTransactionsByRefNo(refNo);
    }
    
    /**
     * 更新库存数量
     */
    private void updateStockQuantity(Long stockId, BigDecimal qty) {
        stockStatusMapper.updateStockQuantity(stockId, qty);
    }
    
    /**
     * 标记交易记录为已删除
     */
    private void markTransactionAsDeleted(Long transactionId) {
        Transaction tr = new Transaction();
        tr.setId(transactionId);
        tr.setIsDeleted(1);
        transactionMapper.updateById(tr);
    }
    
    /**
     * 获取库存状态
     */
    private StockStatus getStockStatus(Long stockId) {
        return stockStatusMapper.selectStockStatusInfo(stockId);
    }
    
    /**
     * 更新交易状态
     */
    private void updateTransactionStatus(Long transactionId, BigDecimal uponCalc) {
        Transaction tr  = new Transaction();
        tr.setId(transactionId);
        tr.setUponCalc(uponCalc);
        tr.setCalcStatus(1);
        transactionMapper.updateById(tr);
    }
    
    /**
     * 更新库存和冻结数量
     */
    private void updateStockAndHoldQuantity(Long stockId, BigDecimal stockQty, BigDecimal holdQty) {
        stockStatusMapper.updateStockAndHoldQuantity(stockId, stockQty, holdQty);
    }
    
    // ==================== 邮件相关方法 ====================
    
    /**
     * 查找有调拨权限的用户
     */
    private List<Map<String, Object>> findUsersWithTransferPermission() {
        return userMapper.selectUsersWithTransferPermission();
    }
    
    /**
     * 查找有损坏报告权限的用户
     */
    private List<Map<String, Object>> findUsersWithDamagePermission() {
        return userMapper.selectUsersWithDamagePermission();
    }
    
    /**
     * 获取调拨物品信息
     */
    private List<Map<String, Object>> getTransferItems(Long requestId, Map<String, Object> user) {
        return transferItemsMapper.selectTransferItems(requestId);
    }
    
    /**
     * 获取调拨申请申请人
     */
    private Map<String, Object> getTransferRequestRequester(Long requestId) {
        return userMapper.selectTransferRequestRequester(requestId);
    }
    
    /**
     * 获取调拨物品信息（用于通知）
     */
    private List<Map<String, Object>> getTransferItemsForNotification(Long requestId) {
        return transferItemsMapper.selectTransferItemsForNotification(requestId);
    }
    
    /**
     * 获取损坏报告信息
     */
    private List<Map<String, Object>> getDamageReportInfo(Long reportId, Map<String, Object> user) {
        return damageReportMapper.selectDamageReportInfo(reportId);
    }
    
    /**
     * 验证邮箱格式
     */
    private boolean isValidEmail(String email) {
        if (email == null || email.trim().isEmpty()) {
            return false;
        }
        String emailRegex = "^[\\s]*\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*[\\s]*$";
        return email.matches(emailRegex);
    }
    
    /**
     * 发送调拨申请邮件
     */
    private void sendTransferRequestEmail(String email, JsonNode transferRequest, List<Map<String, Object>> transferItems, Map<String, Object> user) {
        try {
            String subject = "[IMS] Relocation Request Alert";
            StringBuilder body = new StringBuilder();
            
            // 获取目标站点信息
            String toSiteInfo = getToSiteInfo(transferRequest.get("to_site_id").asLong());
            body.append("Following item(s) will be relocated to ").append(toSiteInfo).append(":<br />");
            
            for (Map<String, Object> item : transferItems) {
                String fromSite = (String) item.get("from_project_code") + 
                                ((String) item.get("from_site_info") != null ? ("-" + item.get("from_site_info")) : "");
                body.append(item.get("item_desc"))
                    .append(" ((From) Project/Site: ").append(fromSite)
                    .append(", Current Stock Qty: ").append(item.get("current_stock_qty"))
                    .append(" ").append(item.get("uom"))
                    .append(", Relocation Qty: ").append(item.get("reloc_qty"))
                    .append(" ").append(item.get("uom"))
                    .append(")<br />");
            }
            
            // 如果有审批权限，添加审批链接
            if ((Boolean) user.get("ops_stock_item_reloc_apprv")) {
                String token = generateToken();
                String link = createApprovalLink(transferRequest.get("id").asLong(), user.get("id"), token);
                body.append("<br />Please click <a href=\"").append(link).append("\">here</a> to approve");
            }
            
            emailService.sendEmail(email, subject, body.toString());
            
        } catch (Exception e) {
            log.error("发送调拨申请邮件失败", e);
        }
    }
    
    /**
     * 发送调拨结果邮件
     */
    private void sendTransferResultEmail(String email, JsonNode transferRequest, List<Map<String, Object>> transferItems) {
        try {
            String status = transferRequest.get("status").asText();
            String subject = "[IMS] Relocation Request " + status;
            StringBuilder body = new StringBuilder();
            
            body.append("Following relocation request(s) have/has been ")
                .append("Approved".equals(status) ? "approved" : "rejected")
                .append(":<br />");
            
            for (Map<String, Object> item : transferItems) {
                String fromSite = (String) item.get("from_project_code") + 
                                ((String) item.get("from_site_info") != null ? ("-" + item.get("from_site_info")) : "");
                String toSite = (String) item.get("to_project_code") + 
                              ((String) item.get("to_site_info") != null ? ("-" + item.get("to_site_info")) : "");
                
                body.append(item.get("item_desc"))
                    .append(" ((From) Project/Site: ").append(fromSite)
                    .append(", (To) Project/Site: ").append(toSite)
                    .append(", Current Stock Qty: ").append(item.get("current_stock_qty"))
                    .append(" ").append(item.get("uom"))
                    .append(", Relocation Qty: ").append(item.get("reloc_qty"))
                    .append(" ").append(item.get("uom"))
                    .append(")<br />");
            }
            
            emailService.sendEmail(email, subject, body.toString());
            
        } catch (Exception e) {
            log.error("发送调拨结果邮件失败", e);
        }
    }
    
    /**
     * 发送损坏报告邮件
     */
    private void sendDamageReportEmail(String email, JsonNode damageReport, List<Map<String, Object>> damageInfo, Map<String, Object> user) {
        try {
            String subject = "[IMS] Damage Report Alert";
            StringBuilder body = new StringBuilder();
            
            body.append("Following damaged item(s):<br />");
            
            Map<String, Object> item = damageInfo.get(0);
            String siteInfo = (String) item.get("project_code") + 
                            ((String) item.get("site_info") != null ? ("-" + item.get("site_info")) : "");
            
            body.append(item.get("item_desc"))
                .append(" (Project/Site: ").append(siteInfo)
                .append(", Damage Qty: ").append(item.get("damage_qty"))
                .append(" ").append(item.get("uom"))
                .append(")<br />");
            
            // 如果有确认权限，添加确认链接
            if ((Boolean) user.get("ops_stock_item_dmg_rec_viewing") && (Boolean) user.get("ops_stock_item_dmg_rec_ack")) {
                String token = generateToken();
                String link = createDamageAckLink(damageReport.get("id").asLong(), user.get("id"), token);
                body.append("<br />Please click <a href=\"").append(link).append("\">here</a> to approve");
            }
            
            emailService.sendEmail(email, subject, body.toString());
            
        } catch (Exception e) {
            log.error("发送损坏报告邮件失败", e);
        }
    }
    
    /**
     * 获取目标站点信息
     */
    private String getToSiteInfo(Long siteId) {
        MstrSite site = mstrSiteMapper.selectById(siteId);
        if (site != null && site.getIsDeleted() == 0) {
            return site.getProjectCode() + 
                   (site.getSiteInfo() != null ? ("-" + site.getSiteInfo()) : "");
        }
        return "";
    }
    
    /**
     * 生成令牌
     */
    private String generateToken() {
        return UUID.randomUUID().toString().replace("-", "");
    }
    
    /**
     * 创建审批链接
     */
    private String createApprovalLink(Long requestId, Object userId, String token) {
        // 这里应该保存令牌到数据库，简化处理
        return "http://localhost:8080/link/approve-reloc-app?id=" + requestId + "&token=" + token;
    }
    
    /**
     * 创建损坏确认链接
     */
    private String createDamageAckLink(Long reportId, Object userId, String token) {
        // 这里应该保存令牌到数据库，简化处理
        return "http://localhost:8080/link/acknowledge-damage?id=" + reportId + "&token=" + token;
    }
} 